home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
dirutl
/
di11.arc
/
DISETUP.C
< prev
Wrap
C/C++ Source or Header
|
1987-12-03
|
32KB
|
784 lines
#include <stdio.h>
#include <dir.h>
#include <dos.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "di.h"
char *Tokenize(char S[],char SepChar);
char *NextMatchFile(char FileSpec[],int Attributes);
NameNode *LastElem(NameNode *List);
NameNode *GetMatchFiles(char *Path,int Attribs);
NameNode *ExpandPath(char Path[]);
NameNode *CreateNameList(void);
NameNode *CatNameLists(NameNode *Target,NameNode *Source);
void AddFileWC(char File[]);
void AddNode(NameNode *Node);
void InsertList(NameNode *Target,NameNode *Source);
void AddCDirs(NameNode *List);
void AddAllWC(char Path[]);
void FirstWild(char Path[],char *Head,char *WildSpec,char *Tail);
void AddString(NameNode *List,char *S);
void DeleteNext(NameNode *List);
void FreeList(NameNode *List);
void MakePathsFull(NameNode **List);
void AddFlag(char *Flag,int *Attribute,ListType *ListSpec);
FlagErr(int ErrWord);
GetFullPath(char *Path);
NullPath(char *Path);
IsRoot(char *Dir);
GetFullDir(char *Path);
IsDir(char *Path);
FindInt(int Arr[],int Targ);
void GetArgs(int argc,char *argv[],int Attribs[],ListType *ListSpec,
NameNode **Files)
/* Converts an argument list to an array of search attribs (Attribs),
a list of filespecs (Files), and a set of listing type specifications
(ListSpec). If any attrib flags are given, the previous values in
Attribs are erased. If any filespecs are given, the previous Files
list is replaced & freed. */
{
int I,
Attrib, /* Search attributes given by one argument */
NumAtts, /* Number of attribute groups found */
FileSpecGiven, /* Whether any argument was a filespec */
OldNum; /* Number of attributes previously given in array */
NameNode *PathList, /* List of paths produced by expanding the wildcards
in a filespec arg */
*List, /* List of paths produced from filespec args */
*CurFile; /* Current end of the path list */
List = CurFile = CreateNameList(); /* Initially set List and CurFile to
point to an empty node */
OldNum = FindInt(Attribs,NO_AT); /* Find number of attribs previously
in Attribs */
NumAtts = 0; /* Initialize current number of attribs to 0 */
FileSpecGiven = FALSE;
for (I = 1; I < argc; I++) { /* For each argument */
if (strchr(FLAGSPECS,argv[I][0]) != NULL) { /* If arg is a flag group */
AddFlag(argv[I],&Attrib,ListSpec); /* Interpret flag
group and set variables */
if (Attrib != NO_AT) { /* If group contained attributes */
ExTest(NumAtts == MAX_ATTS - 1,"Too many attribute groups.");
Attribs[NumAtts++] = Attrib; /* Add attrib and-term to Attribs */
}
}
else {
FileSpecGiven = TRUE;
PathList = ExpandPath(argv[I]); /* Expand wildcards in arg */
if (PathList == NULL)
fprintf(stderr,"Invalid directory in path \"%s\".\n",argv[I]);
else
CurFile = CatNameLists(CurFile,PathList); /* Add all paths
indicated by the arg to the total paths list */
}
}
CurFile = List; /* Get rid of initial empty node */
List = List -> Next;
free(CurFile);
if (FileSpecGiven) { /* If filespecs found, replace original path
list with new list */
FreeList(*Files);
*Files = List;
}
if (ListSpec -> RecSearch) /* If recursive search flag was given, find
all subdirs of the lowest-level dir given in each path and add them to
the list, with each added path having the file name of the path it was
derived from */
AddCDirs(*Files);
if (NumAtts == 0) /* If no attrib flags were given, attrib array is
unchanged; set num of attribs to original num */
NumAtts = OldNum;
Attribs[NumAtts] = NO_AT; /* Mark end of attrib array */
}
void AddFlag(char *Flag,int *Attribute,ListType *ListSpec)
/* Sets Attribute, ListSpec, and More() according to the flags in
Flag. If Flag contains any attribute flags, they are combined to produce
attribute and-term Attribute. Lower case attrib flags are interpreted
as 'true' (a file must have that attribute to match) and the corresponding
bit (as indicated by the FA_* constants) in the low byte of Attribute is
set. Upper case flags are interpreted as 'false' (a file can not have
that attrib to match) and the corresponding bit in the high byte of
Attribute is set. The 'e' flag (everything) sets Attribute to 0. An error
message is printed if both a true and a false flag are given in the same
and-term.
The value of RecSearch and the status of More() are toggled if their
corresponding flags are found. The list specs ListType, Sort, and
LineEnts take on the value of the last flag that applies to them.
No error message is printed if more than one flag for one of them is
found while the env var and command line args are being read, so that
a command line flag can override an env var flag without a message.
If an illegal flag is given, an error message is printed. */
{
static char FlagDesc[] = /* Printed if any illegal flags were given */
" DI: Directory Listing Utility by John H. DuBois III v1.1\n"
"Flags are: Pause during listing; list Long, Wide, or with Full path;\n"
"print 1-6 entries / line if listing wide; search directories reCursively;\n"
"sort first by dIr attrib, eXtension, Time and date, siZe, or Name only;\n"
"Kill headers; print Unused (free) space on device in main header;\n"
"print files with attribs: Everything (print all files), or\n"
"Read only, Hidden, System, Directory, Volume label, Archive.\n";
int I,
Attrib, /* Attrib that one flag translated to */
AttGiven, /* Whether any attributes were given in the flag list */
BadFlag; /* Whether any illegal flags were found in the flag list */
char F; /* Upper case version of flag being interpreted */
*Attribute = 0; /* Initialize to no attributes */
AttGiven = BadFlag = FALSE;
if (Flag[1] == '\0') /* If arg started with a flag specifier but no flags
were given */
fputs("Empty flag.",stderr);
else
for (I = 1; Flag[I] != '\0'; I++) { /* For each flag */
F = UpCase(Flag[I]);
Attrib = NO_AT; /* Initially set Attrib to a value that no
attribute term can have, so that it can be determined if Attrib was
set by a flag */
switch(F) {
case 'F' :
case 'L' :
case 'W' : ListSpec -> ListType = F; break;
case 'X' :
case 'Z' :
case 'N' :
case 'I' :
case 'T' : ListSpec -> Sort = F; break;
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' : ListSpec -> LineEnts = F - '0'; break;
case 'P' : More(More(-2)); break;
case 'U' : ListSpec -> PrintFree = !ListSpec -> PrintFree; break;
case 'K' : ListSpec -> PrintHeaders = !ListSpec -> PrintHeaders;
break;
case 'C' : ListSpec -> RecSearch = !ListSpec -> RecSearch; break;
case 'R' : Attrib = FA_RDONLY; break;
case 'H' : Attrib = FA_HIDDEN; break;
case 'S' : Attrib = FA_SYSTEM; break;
case 'V' : Attrib = FA_LABEL; break;
case 'D' : Attrib = FA_DIREC; break;
case 'A' : Attrib = FA_ARCH; break;
case 'E' : Attrib = 0; break;
default : fprintf(stderr,"Bad flag: %c\n",Flag[I]);
BadFlag = TRUE;
}
if (Attrib != NO_AT) { /* Flag list contained attribute flags */
AttGiven = TRUE;
if (islower(Flag[I])) { /* 'true' flag was given. Check
whether the corresponding 'false' flag has already been set */
if (!FlagErr((*Attribute >> 8) & Attrib))
*Attribute |= Attrib; /* Set the correct bit in lo byte */
}
else /* 'false' flag was given. Check whether the
corresponding 'true' flag has already been set */
if (!FlagErr(*Attribute & Attrib))
*Attribute |= Attrib << 8; /* Set the bit in hi byte */
}
}
if (!AttGiven) /* If no attrib flags found, indicate this */
*Attribute = NO_AT;
if (BadFlag) /* If any bad flags were found, print list of valid flags */
fputs(FlagDesc,stderr);
}
FlagErr(int ErrWord)
/* ErrWord is produced by ANDing the one-byte version of an attrib with
a word containing previously given attribs, with the inverse byte
shifted to the low byte. If an attribute flag with the opposite
value has already been read, the corresponding bit in ErrWord will
be set. If any bits in ErrWord are set, an error message and the flag
are printed and TRUE is returned; otherwise FALSE is returned */
{
if (ErrWord != 0) {
fprintf(stderr,"Conflicting attribute flag: %s\n",
AttribWtoS((char) ErrWord));
return(TRUE);
}
else
return(FALSE);
}
GetEnvParams(int *Cnt,char *Vars[],char *Name)
/* Convert the value of environment var Name to a list of parameters with
the same format as argv and argc. Parameters in the var are separated
by spaces and tabs. A copy of the var value is made with
strdup(); the space after each param is converted to a null char; and a
pointer to the start of each param is put in Vars. The first element in
Vars is set to point to the start of the copied string so it can be freed.
Cnt is set to the number of args found + 1. If the var is not found in
the environment, Cnt is set to 0 and FALSE is returned; otherwise TRUE is
returned.
*/
{
char *Envar, /* Found environment var */
*Value; /* Copied env var */
int Num; /* Number of args found so far + 1 */
*Cnt = Num = 0;
if ((Envar = getenv(Name)) == NULL) /* Get env var */
return(FALSE); /* If not found return FALSE */
else {
Value = strdup(Envar); /* Copy env var value */
Vars[0] = Value; /* Make first pointer point to string */
Num = 1; /* Start with 1 to account for pointer set to Value */
Vars[1] = strtok(Value," \t"); /* Tokenize Value and put
pointers in Vars */
while (Vars[Num] != NULL)
Vars[++Num] = strtok(NULL," ");
*Cnt = Num;
return(TRUE);
}
}
NameNode *ExpandPath(char Path[])
{
NameNode *List, /* Start of the filespec list */
*Temp, /* A node that is to be freed */
*Last, /* End of the filespec list */
*NewDirs; /* The directory list that a wildcard dir spec expanded to */
char Head[MAXPATH], /* The portion of the path before the first component
containing wildcards */
Wild[MAXPATH], /* The first component of the path containing wildcards */
Tail[MAXPATH], /* The portion of the path after the first component containing
wildcards */
Dir[MAXPATH]; /* The current wildcard dir spec being expanded */
Last = List = CreateNameList(); /* Initialize List with an empty node
and make Last be the same node */
strupr(Path); /* Convert Path to all upper case */
strcpy(List -> Name,Path); /* Copy Path to the first node in the list */
AddAllWC(List -> Name); /* Expand all implicit wildcard in the path */
FirstWild(List -> Name,Head,Wild,Tail); /* Find the first wildcard
specification in the path that must be expanded to a list of directories */
while (Tail[0] != '\0') { /* As long as Tail is not a null string, Tail
will contain the last component of the path (the file name). Path
expansion should stop when the file name is reached since only the dir
wildcards are to be expanded. Because all final paths will have the same
number of dirs expanded from wildcards in the path, as soon as one
completely expanded path is found all paths will have been completely
expanded */
strcpy(Dir,Head); /* Make Dir consist of the Head (which will contain no
wildcards) as dir path and Wild as the filename */
strcat(Dir,Wild);
NewDirs = GetMatchFiles(Dir,FA_REALDIR); /* Get the full paths of all
dir names that match Dir */
AddString(NewDirs,Tail); /* Add the unexpanded portion of the path to
all dirs found */
Last = CatNameLists(Last,NewDirs); /* Add the new dirs found to
the end of the dir list */
Temp = List; /* Get rid of the first element of the list (the dir
that has been expanded */
List = List -> Next;
free(Temp);
FirstWild(List -> Name,Head,Wild,Tail); /* Split up the next path in
the list */
}
MakePathsFull(&List); /* Convert relative paths to full path names
and get rid of invalid paths */
return(List);
}
void AddCDirs(NameNode *List)
/* Adds child dirs to List with the same file name. The name of each path in
List is split into directory and filename. All subdirs of each dir are
found and inserted in the list immediately after the parent dir, with
the file name from the original path appended to them. The same proceedure
is performed on each new dir found, so that at the end all decendant dirs
of the dir in the original path will have been added to the list with the
original file name appended. */
{
char Dir[MAXPATH], /* The path being searched for subdirs, with the
original filename replaced by "*.*" */
*NameStrt, /* Start of the filename of the path */
Name[13]; /* The original filename of the path */
NameNode *SubList; /* List of subdirs found */
Name[13] = '\0'; /* If a file name was more than 12 chars, it will be
truncated. Ensures that it will be null terninated */
while (List != NULL) {
strcpy(Dir,List -> Name); /* Copy path so it can be altered */
NameStrt = strrchr(Dir,'\\'); /* Find start of file name */
strncpy(Name,NameStrt,12); /* Save original file name */
strcpy(NameStrt + 1,"*.*"); /* Replace it in path with "*.*"
so all subdirs will be found */
SubList = GetMatchFiles(Dir,FA_REALDIR); /* Find subdirs, but not
"." and ".." entries */
AddString(SubList,Name); /* Add orig file name to all subdirs found */
InsertList(List,SubList); /* Insert list of child dirs immediately after
parent dir, so they will be the next to be searched for child dirs */
List = List -> Next;
}
}
NameNode *GetMatchFiles(char *Path,int Attribs)
/* Finds & makes a list of all files that match Path and Attribs. Returns a
pointer to the list */
{
NameNode *Temp, /* End of the list of matching files */
*List; /* List of matching files */
char *File; /* The name of a matching file */
Temp = List = CreateNameList(); /* Initialize Temp and List to an
empty node */
File = NextMatchFile(Path,Attribs); /* Get the first matching file */
while (File != NULL) { /* Do until no more matching files */
AddNode(Temp); /* Add a new empty node to the list */
Temp = Temp -> Next; /* Move Temp to point to it */
strcpy(Temp -> Name,File); /* Copy the name of the matching file
to the new node */
File = NextMatchFile(NULL,0); /* Get next matching file */
}
Temp = List; /* Get rid of the first empty node */
List = List -> Next;
free(Temp);
return(List);
}
NameNode *CreateNameList()
/* Creates a new NameNode, sets its Next pointer to NULL, and returns
a pointer to it */
{
NameNode *Temp;
Temp = (NameNode *) MallocT(sizeof(NameNode));
Temp -> Next = NULL;
return(Temp);
}
FindInt(int Arr[],int Targ)
/* Searches array Arr for Targ & returns its index */
{
int I;
for (I = 0; Arr[I] != Targ; I++) ;
return(I);
}
void FreeList(NameNode *List)
/* Frees all of the nodes in List */
{
NameNode *Temp;
while (List != NULL) {
Temp = List;
List = List -> Next;
free(Temp);
}
}
void AddAllWC(char Path[])
/* Converts all implicit wildcards in Path, except for those in the last
file name given, to explicit wildcards. A filename
is assumed to exist between every two backslashes and after the last
backslash. If Path contains no backslashes, it is assumed to be one
filename. */
{
char NewPath[MAXPATH], /* The new path as it is being created from Path */
*FSpec, /* The file name being converted */
Temp[12];
int NameStart;
strcpy(NewPath,Path); /* Copy Path to NewPath so that possible
drive spec and leading backslash will be in NewPath */
if (Path[0] != '\0' && Path[1] == ':') /* Find the first file name
in Path (at index 0 or 2, depending on whether a drive was specified */
NameStart = 2;
else
NameStart = 0;
FSpec = Tokenize(Path + NameStart,'\\'); /* Find the first filename in
Path */
if (NewPath[NameStart] == '\\') { /* If Path began with a backslash, the
first name returned by Tokenize will by the null string that preceded the
backslash, which should not be expanded. Call Tokenize again, and make
NewPath end immediately after the first backslash */
FSpec = Tokenize(NULL,'\\');
NewPath[NameStart + 1] = '\0';
}
else
NewPath[NameStart] = '\0'; /* Remove everything except the drive
spec, if given, from NewPath */
while (FSpec != NULL) { /* While there are filenames left to be converted */
strcpy(Temp,FSpec); /* Copy the file name to Temp so it can be
converted */
FSpec = Tokenize(NULL,'\\'); /* Find next file name */
if (FSpec != NULL) /* Convert filename only if it is not the last
file name */
AddFileWC(Temp);
strcat(NewPath,Temp); /* Add name to new path */
strcat(NewPath,"\\"); /* Add a backslash */
}
NewPath[strlen(NewPath) - 1] = '\0'; /* Get rid of the last bckslsh added */
strcpy(Path,NewPath); /* Copy converted path back to Path */
}
void AddFileWC(char File[])
/* Converts the implicit wildcards in File to explicit wildcards. An implicit
file name of "*" exists if File has no file name, and an implicit file
extension of ".*" exists if File has no file ext. If File is "." or "..",
it is not altered. */
{
char *Ext; /* Start of the file ext of File */
Ext = strchr(File,'.');
if (Ext == File && !CPDir(File) || File[0] == '\0') /* If File starts with
a dot and is not the current or parent dir ("." or ".."), then it has no
file name; make the file name "*". */
Insert(File,"*",0);
if (Ext == NULL) /* If there was no dot in File, it has no file ext;
make the file ext ".*" */
strcat(File,".*");
}
char *Tokenize(char S[],char SepChar)
/* Converts S to tokens. On the first call, S should be the string to tokenize;
on subsequent calls it should be null. S is a string of tokens separated
by single instances of SepChar. If two SepChar's occur adjacent to each
other, a null token ("") is assumed to exist between them. If S has a
leading or trailing SepChar, a null token is assumed to exist before or
after the string, respectively. SepChar can be different between calls.
After each call to Tokenize, a null is written immediately after the token
found and a pointer to its start is returned. Null tokens are returned as
empty strings. When no more tokens are found, a NULL pointer is returned.
*/
{
static char *List; /* Start of list of tokens */
char *Pos, /* Position of end of current token */
*Token; /* Start of token */
if (S != NULL) /* If first call to function, set List to string given */
List = S;
Token = List; /* Current token starts at start of List */
if (List != NULL) { /* If some tokens are left */
Pos = strchr(List,SepChar); /* Find end of token */
if (Pos == NULL) /* If no more tokens, the next call will return NULL */
List = NULL;
else {
*Pos = '\0'; /* Otherwise, add null termination to current token
and make List point to start of next token */
List = Pos + 1;
}
}
return(Token);
}
void FirstWild(char Path[],char *Head,char *WildSpec,char *Tail)
/* Finds the first wildcard filename in Path. The portion of the path
preceeding that filename (if any), including trailing backslash, is
copied to Head. The wildcard filename (without leading or trailing
backslashes) is copied to WildSpec. The portion of the path after
the wildcard filename (including leading backslash) is copied to Tail */
{
char *PostSep,
*PreSep,
*FirstWC;
strcpy(Head,Path); /* Copy Path to Head so it can be altered */
FirstWC = Head + strcspn(Head,"*?"); /* Make FirstWC point to the first
wildcard in Head */
if (*FirstWC == '\0') { /* If no wildcards found, leave the entire
string in Head and make WildSpec and Tail null strings */
WildSpec[0] = '\0';
Tail[0] = '\0';
}
else {
PostSep = strchr(FirstWC,'\\'); /* Find the first backslash after the
first wildcard */
if (PostSep != NULL) { /* If there was one, then it is the start of
the tail and the end of the first wildcard spec */
strcpy(Tail,PostSep);
*PostSep = '\0';
}
else
Tail[0] = '\0'; /* If not, make Tail a null string */
PreSep = strrchr(Head,'\\'); /* Find the first backslash before the
the first wildcard */
if (PreSep != NULL) { /* If there was one, the char after it is the
start of the the first wildcard spec and the end of the Head */
strcpy(WildSpec,PreSep + 1);
*(PreSep + 1) = '\0';
}
else {
strcpy(WildSpec,Head); /* If not, everything in Head is the first
wildcard spec */
Head[0] = '\0';
}
}
}
void AddString(NameNode *List,char *S)
/* Adds string S to every name in List */
{
while (List != NULL) {
strcat(List -> Name,S);
List = List -> Next;
}
}
void InsertList(NameNode *Target,NameNode *Source)
/* Inserts list Source into the list in which Target is a node, immediately
after target. */
{
NameNode *Next;
if (Source != NULL) {
Next = Target -> Next;
Target -> Next = Source;
LastElem(Source) -> Next = Next;
}
}
NameNode *CatNameLists(NameNode *Target,NameNode *Source)
/* Target points to the last node in a list. Catenates Source to Target
and returns a pointer to the last node of the new list */
{
ExTest(Target == NULL,"Error: Null Target in CatNameLists().");
Target -> Next = Source;
return(LastElem(Target));
}
NameNode *LastElem(NameNode *List)
/* Returns a pointer to the last element of List */
{
ExTest(List == NULL,"Error: Null pointer passed to LastElem()");
while(List -> Next != NULL)
List = List -> Next;
return(List);
}
void AddNode(NameNode *Node)
/* Creates a new node; links Node to it; and makes its Next pointer null */
{
ExTest(Node == NULL,"NULL pointer passed to AddNode");
Node -> Next = (NameNode *) MallocT(sizeof(NameNode));
Node -> Next -> Next = NULL;
}
char *NextMatchFile(char FileSpec[],int Attributes)
/* Finds files that match FileSpec and have all attributes indicated by
Attributes, and returns the full path of the file,
including the drive and directory given in FileSpec. On the first call,
FileSpec and Attribs are given; on subsequent calls FileSpec should be
NULL. The found file is put in a static buffer and a pointer to the
buffer is returned. If no matching file is found, a null pointer is
returned. */
{
static char File[MAXPATH], /* Full file name buffer */
Drive[MAXDRIVE],Dir[MAXDIR]; /* Drive and dir given in the filespec, to
be added to each file found */
static struct ffblk FFBlk; /* Structure for directory searching routine */
char Name[MAXFILE],Ext[MAXEXT]; /* Name and extension of found file */
int Done; /* Whether dir searching routine found a matching file */
static int Attribs, /* Saves Attributes between calls */
RealDir; /* Search for real dirs only */
if (FileSpec != NULL) { /* First call to function */
fnsplit(FileSpec,Drive,Dir,NULL,NULL); /* Get drive & dir of filespec */
if (Attributes & FA_REALDIR) { /* If one of the attributes given is
the psuedo-attrib FA_REALDIR (match real dirs only, not "." or "..")
then set the variable that will save the search attribs between calls
to Attributes, with the psuedo-attrib replaced with the dir attrib,
and set RealDir */
Attribs = (Attributes & ~FA_REALDIR) | FA_DIREC;
RealDir = TRUE;
}
else { /* Save attribs */
Attribs = Attributes;
RealDir = FALSE;
}
Done = findfirst(FileSpec,&FFBlk,Attribs); /* Find first match file */
}
else /* Use FFBlk set up by previous call */
Done = findnext(&FFBlk);
while (!Done && ((FFBlk.ff_attrib & Attribs) != Attribs ||
RealDir && CPDir(FFBlk.ff_name))) /* Find next file that has all of the
attribs specified in Attribs and, if RealDir is set, is not the current
or parent dir entry ("." or "..") */
Done = findnext(&FFBlk);
if (Done) /* If no more matching files return NULL */
return(NULL);
else {
fnsplit(FFBlk.ff_name,NULL,NULL,Name,Ext); /* Split matching file name
into Name & Extension */
fnmerge(File,Drive,Dir,Name,Ext); /* Merge Name & Ext with previously
given Drive & Dir */
return(File);
}
}
void MakePathsFull(NameNode **List)
/* Converts the relative paths given in List to full path names, and deletes
invalid paths from the list. If paths are removed from the front of the
list, List is changed to point to the new start of the list */
{
NameNode *Last, /* The last path converted */
*Temp; /* Pointer to list as it is stepped through */
while (*List != NULL && !GetFullPath((*List) -> Name)) { /* Find the first valid
path in List (deleting invalid ones) and convert it to a full path */
Temp = *List;
*List = (*List) -> Next;
free(Temp);
}
if (*List != NULL) { /* If any valid dirs were given */
Temp = (*List) -> Next; /* Start with the next node, since the current
one has already been converted */
Last = *List; /* The previous loop insured that there is a 'last'
node that can have its Next pointer moved beyond the current node, in
order to delete that node */
while (Temp != NULL) { /* For all of the rest of the paths in the list */
if (GetFullPath(Temp -> Name)) { /* If path is valid */
Last = Temp; /* Make Last point to the current
path, then move to the next path */
Temp = Temp -> Next;
}
else { /* If the path is not valid */
DeleteNext(Last); /* Delete the current path from the list
by making the Next pointer of the previous node point the next
node and freeing the current node */
Temp = Last -> Next; /* Move to the next path */
}
}
}
}
void DeleteNext(NameNode *List)
/* Deletes the node that follows List by making List's Next pointer point to
the node beyond the next node, and freeing the deleted node */
{
NameNode *Temp; /* Node to be freed */
ExTest(List == NULL || List -> Next == NULL,"Null pointer to DeleteNode");
Temp = List -> Next;
List -> Next = Temp -> Next;
free(Temp);
}
GetFullPath(char *Path)
/*
Given a relative path to a file or directory, finds the full path name
of the file or directory and replaces the original string with it.
If a drive is not specified in the path, the current drive is used.
Returns TRUE if the file is found, otherwise FALSE.
*/
{
char Drive[MAXDRIVE],Dir[MAXDIR],FileName[MAXFILE],Ext[MAXEXT], /* Used to
split up and reassemble path */
FindPath[MAXPATH]; /* New path */
int Comps; /* Components found in path */
strcpy(FindPath,Path); /* Make working copy of Path */
if (FindPath[0] == '\0' || FindPath[1] == ':' && strlen(FindPath) == 2)
/* If no path or only a drive is given, make path be the current
directory on the default or given drive. */
strcat(FindPath,".\\");
else if (IsDir(FindPath) && FindPath[strlen(FindPath) - 1] != '\\')
/* If path is a directory, append a backslash to it to indicate this */
strcat(FindPath,"\\");
Comps = fnsplit(FindPath,Drive,Dir,FileName,Ext); /* Split path into its
components */
strcpy(FindPath,Drive); /* Generate path pointing to given directory
or parent dirctory of given file */
strcat(FindPath,Dir);
strcat(FindPath,".");
if (strcmp(FileName,".") == 0 || !GetFullDir(FindPath)) /* Convert
directory path to full dir name; if dir specified in path was invalid, or
specified a parent directory beyond the root directory, return FALSE */
return(FALSE);
if (!(Comps & DRIVE)) { /* If a drive was not specified, make path
drive be the current drive */
Drive[0] = getdisk() + 'A';
Drive[1] = ':';
}
if (!(Comps & FILENAME)) /* If no file name given, make file name "*" */
strcpy(FileName,"*");
if (!(Comps & EXTENSION)) /* if no file ext given, make file ext ".*" */
strcpy(Ext,".*");
fnmerge(Path,Drive,FindPath,FileName,Ext); /* Create full path from comps */
return(TRUE);
}
GetFullDir(char *Path)
/* Given a path to a directory, converts it to a full directory name. If
given path did not point to a dir, returns FALSE; else returns TRUE */
{
struct ffblk FFBlk; /* Structure for directory searching routine */
char Dir[MAXPATH]; /* Temp storage of full path */
if (!IsDir(Path)) /* If invalid directory, return FALSE */
return(FALSE);
Dir[0] = '\0'; /* Clear directory string */
while (!findfirst(Path,&FFBlk,0x3f)) { /* Get name of directory
pointed to by Path until no more directories can be found */
if (!IsRoot(Path)) { /* Check whether directory name found is the
name of the dir that is at the root of the drive given in the path,
which it could be if the drive is a substituded drive. If not,
insert the name followed by a backslash at the begining of Dir */
Insert(Dir,"\\",0);
Insert(Dir,FFBlk.ff_name,0);
}
strcat(Path,"\\.."); /* Append "\.." to Path so it will point
to the parent directory (if it exists) of the dir just found */
}
Insert(Dir,"\\",0); /* Make Dir have a leading backslash */
strcpy(Path,Dir); /* Move full dir name to Path */
return(TRUE);
}
IsRoot(char *Dir)
/* Returns TRUE if Dir is a path to the root of a real or substituted drive,
or is an invalid directory. Otherwise returns FALSE. */
{
struct ffblk FFBlk; /* For dir searching routine */
char Temp[MAXPATH]; /* Path to parent of Dir, if it exists */
strcpy(Temp,Dir);
strcat(Temp,"\\..\\*.*"); /* Make Temp point to parent of Dir */
return(findfirst(Temp,&FFBlk,0x3f)); /* Return TRUE if Dir has no parent. */
}
IsDir(char *Path)
/* Returns true if Path is a directory, otherwise false. */
{
char Temp[MAXPATH]; /* Test string */
struct ffblk FFBlk; /* For directory searching routine */
strcpy(Temp,Path);
if (Temp[0] != '\0' && Temp[strlen(Temp) - 1] != '\\') /* If string is
not null and does not end in a backslash, append a backslash to it so it
will specify a directory */
strcat(Temp,"\\");
strcat(Temp,"*.*"); /* Make temp specify any file in the given directory */
return(!findfirst(Temp,&FFBlk,0x3f) || NullPath(Path)); /* If any files
are found, or it is a null path (contains only single .'s or backslashes)
it must be a directory. The only directory that does not have
any files is a root dir without ordinary files, directories, system files
or volume label. A path to such a directory must be a null path. */
}
NullPath(char *Path)
/* Checks whether Path is a null path (contains only single '.s and
backslashes). Returns TRUE if so, else returns FALSE. */
{
char Temp[MAXPATH];
if (DriveSpeced(Path))
strcpy(Temp,Path + 2);
else
strcpy(Temp,Path);
strcat(Temp,"\\"); /* Pad string with '\' so strstr will work despite
its bug */
return(strspn(Temp,"\\.") == strlen(Temp) && strstr(Temp,"..") == NULL);
/* Check that temp contains only \'s and .'s, and no two .'s are
adjacent */
}